package cronservice

import (
	"github.com/gogf/gf/os/glog"
	"go-middle/app/common/model/cron"
	"go-middle/app/common/model/cron_log"
	"time"
)

//TaskResult 任务执行返回结果
type TaskResult struct {
	Result     string
	Err        error
	RetryTimes int
}

// 创建任务日志
func createTaskLog(taskModel cron.Task) (int64, error) {
	taskLogModel := new(cron_log.Entity)
	taskLogModel.CronId = taskModel.Id
	taskLogModel.CronName = taskModel.Name
	taskLogModel.Command = taskModel.Command
	taskLogModel.Pattern = taskModel.Pattern
	taskLogModel.Protocol = taskModel.Protocol
	taskLogModel.Status = 0
	taskLogModel.Timeout = taskModel.Timeout
	taskLogModel.StartTime = time.Now().Unix()
	taskLogModel.ServerId = taskModel.ServerId
	res, err := taskLogModel.Insert()
	if err != nil {
		return 0, err
	}
	LastInsertId, err := res.LastInsertId()
	return LastInsertId, err
}

// 更新任务日志
func updateTaskLog(taskLogId int64, taskResult TaskResult) error {
	taskLogModel, err := cron_log.FindOne("id=?", taskLogId)
	if err != nil {
		return err
	}
	taskLogModel.Result = taskResult.Result
	taskLogModel.RetryTimes = taskResult.RetryTimes
	if taskResult.Err != nil {
		taskLogModel.Status = 1
		if taskResult.Result == "" {
			taskLogModel.Result = taskResult.Err.Error()
		}
	} else {
		taskLogModel.Status = 2
	}
	taskLogModel.EndTime = time.Now().Unix()
	taskLogModel.RunTime = taskLogModel.EndTime - taskLogModel.StartTime
	_, err = taskLogModel.Update()
	return err
}

// 任务前置操作
func beforeExecJob(taskModel cron.Task) (taskLogId int64) {
	taskLogId, err := createTaskLog(taskModel)
	if err != nil {
		glog.Error("[gcron] 任务开始执行#写入任务日志失败-", err)
		return
	}
	glog.Debugf("[gcron] 任务命令-%s", taskModel.Command)
	return
}

// 任务执行后置操作
func afterExecJob(taskResult TaskResult, taskLogId int64) {
	err := updateTaskLog(taskLogId, taskResult)
	if err != nil {
		glog.Error("[gcron] 任务结束#更新任务日志失败-", err)
	}
	//发邮件通知
}

// 执行具体任务
func execJob(handler Handler, taskModel cron.Task) TaskResult {
	// 默认只运行任务一次
	var execTimes int = 1
	if taskModel.RetryCount > 0 {
		execTimes += taskModel.RetryCount
	}
	var i int = 0
	var output string
	var err error
	for i < execTimes {
		output, err = handler.Run(taskModel)
		if err == nil {
			return TaskResult{Result: output, Err: err, RetryTimes: i}
		}
		i++
		if i < execTimes {
			glog.Warningf("[gcron] 任务执行失败#任务id-%d#重试第%d次#输出-%s#错误-%s", taskModel.Id, i, output, err.Error())
			if taskModel.RetryInterval > 0 {
				time.Sleep(time.Duration(taskModel.RetryInterval) * time.Second)
			} else {
				// 默认重试间隔时间，每次递增1分钟
				time.Sleep(time.Duration(i) * time.Minute)
			}
		}
	}
	return TaskResult{Result: output, Err: err, RetryTimes: taskModel.RetryCount}
}

//创建定时任务
func createJob(taskModel cron.Task) func() {
	handler := createHandler(taskModel)
	if handler == nil {
		return nil
	}
	taskFunc := func() {
		taskLogId := beforeExecJob(taskModel)
		if taskLogId <= 0 {
			return
		}
		glog.Infof("[gcron] 开始执行任务#%s#命令-%s", taskModel.Name, taskModel.Command)
		taskResult := execJob(handler, taskModel)
		glog.Infof("[gcron] 任务完成#%s#命令-%s", taskModel.Name, taskModel.Command)
		afterExecJob(taskResult, taskLogId)
	}
	return taskFunc
}
